
from util_pos import *
g_paths = []
add_library('sound')
w, h = 600, 520
bubble_log = {}
brick_log = {}
bubble_time = {}
exptime = 3000
endtime = 3100
bots = []
i = 0
grid_w = 40
grid_h = 40
game_state = {'update': 0}
n_bot = 5
img_brick = {}
img_object = {}
position_brick = {}
position_brick['gongfu'] = []
position_brick['box'] = []
position_object = {'number': [], 'speed': [], 'power': []}
player_state = {'obj': {'number': 0, 'speed': 0, 'power': 0}, 'speed': 10}
bubble_power = {}  # x,y : 1
boom_log = {}
lrud = ['left','right','up','down']
boom_range = {}# {p: []}}

target_pool = []
def get_path(node_father,end_node):
    
    cur = end_node
    paths = [cur]
    while cur in node_father:
        cur = node_father[cur]
        paths.insert(0,cur)
    return paths

def Astar_finder(startp,endp,forbids):
    node_father = {}
    print(('start',startp,endp)) 
    has_visited = []
    search_pos = [startp]
    cur = ''
    if startp in forbids or endp in forbids:
        return []
    assert startp not in forbids
    assert endp not in forbids
    while search_pos!=[] and cur != endp:
        search_pos = sorted(search_pos,key=lambda x : abs(x[0]-endp[0])+abs(x[1]-endp[1]) ,reverse=True)
        cur = search_pos.pop()
        has_visited.append(cur)
        dmap = {'left':(-1,0),'right':(1,0),'up':(0,-1),'down':(0,1)}
        for direction, displacement in dmap.items():
            dx,dy =displacement
            cx,cy = cur
           
            if 0<= cx+dx <15 and 0<= cy+dy<13:
                if (cx+dx,cy+dy) in forbids:
                    continue
                if (cx+dx,cy+dy) not in has_visited:
                    search_pos.append((cx+dx,cy+dy))
                    node_father[(cx+dx,cy+dy)] = cur
        
        if len(search_pos)>15*13:
            break
    
    if  len(has_visited) != len(set(has_visited)):
        print('!!no eq')
    return get_path(node_father,endp)
    #return has_visited,node_father
        

    

def get_bubble_limit():
    return player_state['obj']['number'] + 1


def new_player_state():
    return {'obj': {'number': 0, 'speed': 0, 'power': 4}, 'speed': 10,'s':0,'current_direction':'down','isBot':True}


def random_choice(list_a):
    r = int(random(0, len(list_a)))
    return list_a[r]

def get_speed(d):
    return d['obj']['speed'] * 0.5 + 1
def get_player_speed():
    return get_speed(player_state) 


def pick_a_brick(other):
    bricks = position_brick['gongfu']
    bricks = [u for u in bricks if u not in other]
    if len(bricks) == 0:
        return None
    r = int(random(0, len(bricks)))
    return bricks[r]


def new_bot():
    global i
    global position_brick
    p = PVector(0.5*w -120,300)#(0.5*w - 200 *random(-1,1), 100)
    #p = PVector()
    bricks = position_brick['gongfu']
    d = {'id': i, 'position': p, 'state': 'alive', 'target': None, 'bubbles': [], 'player_state': new_player_state()}
    if len(bricks) > 0:
        r = int(random(0, len(bricks)))
        d['target'] = bricks[r]
    i += 1
    return d

def bot_add_obj(bot, obj):
    bot['player_state']['obj'][obj]+=1
    return bot

def get_bot_bubble_limit():
    return 1


def bot_put_bubble(bot_dict, p):
    print('put a bubble')
    if len(bot_dict['bubbles']) < 122:#get_bot_bubble_limit():
        if p not in bubble_time:
            bubble_log[p] = True
            bot_dict['bubbles'].append(p)
            bubble_time[p] = millis()
            bubble_power[p] = bot_dict['player_state']['obj']['power'] + 2


def boom_hit_player(boom, p_bot):
    # boom   topleft
    # p bot vector
    x, y = boom
    if abs(x - p_bot.x) < 20 and abs(y - p_bot.y) < 20:
        return True
    return False


def bots_bubble(boom):
    for bot in bots:
        p_bot = bot['position']
        if boom_hit_player(boom, p_bot):
            bot['state'] = 'Dead!'
            for obj,num in bot['obj'].items():
                x_r = random(0,w)
                y_r = random(0,h)
                x_r,y_r = get_grid_idx(x_r,y_r)
                position_object[obj].append((x_r,y_r))
    return


def bots_bubble_grid(boom):
    c, r = boom
    y, x = get_grid_centre(r, c)
    bots_bubble((x, y))


def limit_pos(x, y, res):
    for direction, pos in res.items():
        if direction == 'left':
            x = max(x, pos[0])
        if direction == 'up':
            y = max(y, pos[1])
            stroke(255, 0, 0)
            line(0, pos[1], w, pos[1])
        if direction == 'right':
            x = min(x, pos[0])
        if direction == 'down':
            stroke(0, 255, 0)
            y = min(y, pos[1])
            line(0, pos[1], w, pos[1])
    return x, y

             
    

def setup():
    size(780, h + 65)

    global player_index
    global player_position
    global current_direction
    global bg_img
    global player
    
    global bubbles
    global boom
    global bgm
    bgm = SoundFile(this, 'water.mp3')
    
    global winbgm
    winbgm = SoundFile(this, 'PlayerWin.mp3')
    global boom_voice
    boom_voice = SoundFile(this, 'boom.wav')
    global obj_voice
    obj_voice = SoundFile(this, 'getobj.wav')
    bgm.amp(0.01)
    bgm.loop()
    bubbles = []
    player = {'left': [], 'right': [], 'up': [], 'down': []}

    current_direction = 'down'
    player_position = PVector(100, 200)
    player_index = {'left': 0, 'right': 0, 'up': 0, 'down': 0
                    }
    for i in range(n_bot):
        bot = new_bot()
        bots.append(bot)
    for direction in player.keys():
        for i in range(4):
            directioni = {'left':1,'right':2,'up':3,'down':0}.get(direction)
            img = loadImage('walk_55_{}_{}.png'.format(directioni, i))
            # print(img.width,img.height)#44, 59
            player[direction].append(img)
    global player2_img
    player2_img= {'left': [], 'right': [], 'up': [], 'down': []}            
    for direction in player2_img.keys():
        for i in range(4):
            directioni = {'left':1,'right':2,'up':3,'down':0}.get(direction)
            img = loadImage('walk_54_{}_{}.png'.format(directioni, i))
            player2_img[direction].append(img)
    global bot_img
    bot_img = {'left': [], 'right': [], 'up': [], 'down': []}
    for direction in bot_img.keys():
        for i in range(4):
            directioni = {'left':1,'right':2,'up':3,'down':0}.get(direction)
            img = loadImage('walk_13_{}_{}.png'.format(directioni, i))
            # print(img.width,img.height)#44, 59
            bot_img[direction].append(img)    
    bg_img = loadImage('land.jpg')
    global brick_img
    brick_img = loadImage('brick_y.png')
    global p2
    p2 = loadImage('role1_4_1.png')
    global bubble_img
    bubble_img = loadImage('bomb3.png')
    bubble_img3 = bubble_img
    bubble_img2 = loadImage('bomb2.png')
    bubble_img1 = loadImage('bomb1.png')
    global bubble_animes
    bubble_animes = [bubble_img1,bubble_img2,bubble_img3,bubble_img2]
    boom = loadImage('mid_boom.png')
    
    global mouse_img
    mouse_img = loadImage('mouse.png')
    global bg_window
    bg_window = loadImage('window.png')
    player['bg'] = bg_img
    img_brick['gongfu'] = loadImage('pig/elem11_stand_0_0.png')
    img_brick['box'] = loadImage('pig/elem12_stand_0_0.png')
    img_object['number'] = loadImage('number.png')
    img_object['power'] = loadImage('power.png')
    img_object['speed'] = loadImage('speed.png')

    for col in [2, 3, 4, 5, 9, 10, 11, 12]:
        row = 12
        position_brick['box'].append((col, row))
    make_map(position_brick)
    player['bubbles'] = []
    player['bricks'] = []
    player['s'] = 0
    global player2
    player2 = new_bot()
    player2['player_state']['isBot'] = False

def add_mile(s):
    global player
    player['s']+=s
def get_mile():
    global player
    return player['s']

def get_walk_img_i():
    s = get_mile()
    s = int(s/8)
    return s%4

def add_bot_mile(bot,s):
    bot['player_state']['s']+=s
    
def get_bot_mile(bot):
    return bot['player_state']['s']

def get_bot_walk_img_i(bot):
    s = get_bot_mile(bot)
    s = int(s/8)
    return s%4

def get_bot_img(bot):
    global bot_img
    dir = bot['player_state']['current_direction']
    walk_img_i = get_bot_walk_img_i(bot)
    return bot_img[dir][walk_img_i]

def get_p2_img(bot):
    global player2_img
    dir = bot['player_state']['current_direction']
    walk_img_i = get_bot_walk_img_i(bot)
    return player2_img[dir][walk_img_i]
        

def limit_player(x, y):
    return max(min(x, w - 20), 20), max(min(y, h - 20), 20)


def brick_bubble_player_limit(pp, direction):
    v =1
    c, r = get_grid_idx(pp.x, pp.y)
    forbids = player['bubbles'] + position_brick['gongfu'] + position_brick['box']
    # if direction == 'left':
    #     pp.x -= 10
    #     if (c - 1, r) in forbids:
    #         pp.x = max(grid_w * (c) + 0.5 * grid_w, pp.x)
    # if direction == 'right':
    #     pp.x += 10
    #     if (c + 1, r) in forbids:
    #         pp.x = min(grid_w * (c + 1) - 0.5 * grid_w, pp.x)
    # if direction == 'up':
    #     pp.y -= 10
    #     if (c, r - 1) in forbids:
    #         pp.y = max(grid_h * (r) + 0.5 * grid_h, pp.y)
    # if direction == 'down':
    #     pp.y += 10
    #     if (c, r + 1) in forbids:
    #         pp.y = min(grid_h * (r + 1) - 0.5 * grid_h, pp.y)
    dir2dxdy = {'left':(-1,0),'right':(1,0),'up':(0,-1),'down':(0,1)}
    dx,dy = dir2dxdy[direction]
    if (c+dx,r+dy) in forbids:
        if dx+dy >0:fun = min
        if dx+dy < 0 : fun = max
        if direction in ['left','right']:
            pp.x = fun(grid_w * (c + 0.5)   , pp.x+ dx*v)
        else:
            pp.y = fun(grid_w * (c + 0.5)   , pp.y+ dy*v)
    return pp

def bot_walk(bot,current_direction):
    bot['player_state']['current_direction'] = current_direction#['left','right','up','down'][r]
    v = get_speed(bot['player_state']) 
    dirs = ['left', 'right', 'up', 'down']
    r = dirs.index(current_direction)
    ds = [(-v, 0), (v, 0), (0, -v), (0, v)]
    dx, dy = ds[int(r)]
    add_bot_mile(bot,v)
    pp = bot['position']
 
    pp = brick_bubble_player_limit(pp, dirs[int(r)])
    bot['position'].x, bot['position'].y = limit_player(pp.x, pp.y)
def addTargetOnBot(bot):
    #bot['target']  = (4,4)
    if  bot['target'] :
        if bot['target'] not in position_brick['gongfu']:
            bot['target'] = None
    if bot['target'] not in position_brick['gongfu'] or not bot['target']:
        brick = pick_a_brick(target_pool)
        if brick:
            bot['target'] = brick
            target_pool.append(brick)

def bots_move2():
    for bot in bots:
        if bot['player_state']['isBot'] is False:
            continue
        if bot['state'] !='alive':
            continue
        v =2
        addTargetOnBot(bot)
        
        r = random(0, 4)
        ds = [(-v, 0), (v, 0), (0, -v), (0, v)]
        dx, dy = ds[int(r)]
        dirs = ['left', 'right', 'up', 'down']
        col, row = bot['target'][0], bot['target'][1]
        botx_grid, boty_grid = get_grid_idx(bot['position'].x, bot['position'].y)
        p = (botx_grid, boty_grid)
        
        objs_nearby = find_nearest_obj(p, 4, position_object)
        bubbls = find_boom_place(p, 2, bubble_time)   
        if len(objs_nearby) > 0:
            pass
        elif len(bubbls) > 0:
            
          

            print('has bubble')
        else:
            targety, targetx = get_grid_centre(row, col)
            can_dirs = []
            if bot['position'].x < targetx:
                can_dirs.append(1)
            else:
                can_dirs.append(0)
            d = 1000000000
            nearest = -1
            datas = []
            for i in range(len(dirs)):
                ds = [(-v, 0), (v, 0), (0, -v), (0, v)]
                dx, dy = ds[i]
                x2, y2 = (bot['position'].x + dx, bot['position'].y + dy)
                gx, gy = get_grid_idx(x2, y2)
                if (gx, gy) in bubble_time or (gx, gy) in position_brick['gongfu']:
                    continue
                r2 = (targety - y2) ** 2 + (targetx - x2) ** 2
                if r2 < d:
                    d = r2
                    nearest = i
                datas.append((i, r2 ** 0.5))
            datas = sorted(datas, key=lambda x: x[1])
            print(datas)
            if len(datas) == 0:
                #print('no direct')
                r = random(0, 4)
            else:
                nearest = datas[0][0]
                if nearest != -1:
                    r = nearest
    
                r  = nearest
            
                
            bot['player_state']['current_direction'] = ['left','right','up','down'][r]
            dx, dy = ds[int(r)]
            add_bot_mile(bot,v)
            pp = bot['position']
    
            pp = brick_bubble_player_limit(pp, dirs[int(r)])
            bot['position'].x, bot['position'].y = limit_player(pp.x,pp.y)
def bot_displacement(bot,dx,dy):
    pp = bot['position']
    bot['position'].x, bot['position'].y  = pp.x +dx,pp.y+dy

    print({'602  dxdy':(dx,dy)})
    #pp=brick_bubble_player_limit(pp, dirs[int(r)])
    #bot['position'].x, bot['position'].y = limit_player(pp.x,pp.y)
    return 

def get_dir(botx_grid,boty_grid,destination):
    tx,ty = destination
    if not 0<=tx<15 or not 0<=ty<13 :
        print('invalid!!!!')
        print(tx,ty)
        return None
        
        
    if (botx_grid,boty_grid) == destination:
        print('tmd you already here')
        return None
    paths = Astar_finder((botx_grid,boty_grid),destination,position_brick['gongfu'])
    if paths == []:
        print('path = []')
        return None 
    global g_paths
    g_paths = paths
    print('l',len(paths))
    
    safex ,safey = paths[1]
    print('bx,by,target x y ',botx_grid,boty_grid,safex,safey)
    if safex < botx_grid :
        print('-------left')
        return 0 
    if safex > botx_grid :
        print('--------right')
        return 1
    if safey < boty_grid :
        print('--------up')
        return 2
    if safey > boty_grid :
        print('---------down')
        return 3
    print('no result',botx_grid,boty_grid,safex,safey)
def get_batch_grid(me,bots):
    grid = []
    for bot in bots:
        if bot == me:
            continue
        x,y = get_grid_idx(bot['position'].x,bot['position'].y)
        grid.append((x,y))
    return grid

def bot_attract_other(p,bot,other_bots):
    if any([in_bot_attract_range(p,get_bot_power(bot),(attx,atty)) for attx,atty in get_batch_grid(bot,other_bots)]):
        return True
    return False
def bots_move():
    # if random(0,4)<1:
    #     return
    v_ = 2
    global player_position
    px, py = player_position.x, player_position.y
    global player
    mex, mey = get_grid_idx(px, py)
    for bot in bots:
        
        if bot['player_state']['isBot'] is False:
            continue
        
        if bot['state'] !='alive':
            continue
        v =2
        #v = get_speed(bot['player_state']) 

        addTargetOnBot(bot)
        # bot['target'][1] = 10

        r = random(0, 4)
        ds = [(-v, 0), (v, 0), (0, -v), (0, v)]
        #dx, dy = ds[int(r)]
        dirs = lrud
        if bot['target']:
            col, row = bot['target'][0], bot['target'][1]
        botx_grid, boty_grid = get_grid_idx(bot['position'].x, bot['position'].y)
        p = (botx_grid, boty_grid)
        
        objs_nearby = find_nearest_obj(p, 4, position_object)
        bubbls = find_boom_place(p, 2, bubble_time)   
        
          
           
          
        if len(bubbls) > 0:
            
            bubble = bubbls[0]
            safes_ = find_nearest_safe(p, bubble, 2)
            
            if len(bubbls)>1:
                for bubble in bubbls:
                    safes = find_nearest_safe(p, bubble, 2)
                    safes_ = [u for u in safes if u in safes_]
            
            safes = [s for s in safes_ if s not in player['bricks'] and s != bubble]
            if len(safes)>0:
                safe = safes[0]
                print('line511')
                if (botx_grid, boty_grid) in player['bricks']:
                    print('on brick')
                elif safe in player['bricks']:
                    print('safe on brick')
                if (botx_grid, boty_grid) ==safe:
                    continue
                r = get_dir(botx_grid, boty_grid,safe)
                if r is not None:
                    bot['player_state']['current_direction'] = lrud[r]
                    dx, dy = ds[int(r)]
                    print({'to hide bomb!!  dxdy':(dx,dy)})
                    add_bot_mile(bot,v)
                    pp = bot['position']
                    bot_displacement(bot,dx,dy)
                else:
                    print('no r',r)
                continue
                     
            else:
                print('no place to hide')
                continue
        # 有道具  
        elif len(objs_nearby) > 0:
            
            safe = objs_nearby[0]
            print('objs_nearby')
            r = get_dir(botx_grid, boty_grid,safe)
            if r is not None:
                bot['player_state']['current_direction'] = lrud[r]
                dx, dy = ds[int(r)]
                add_bot_mile(bot,v)
                pp = bot['position']
                bot_displacement(bot,dx,dy)
            else:
                print(548,r)
            continue
        # 在 目标砖块旁边
        elif   bot['target'] and is_neighbood((botx_grid, boty_grid), (col, row)) and not p in bubble_time:
            bot_put_bubble(bot, p)
            print('beside the target brick')
            continue
        # 
        elif bot['target']:
            print('-----at else')
 
            #print('nothing')
            targety, targetx = get_grid_centre(row, col)
    
            # d = 1000000000
            # nearest = -1
            # datas = []
            # for i in range(len(dirs)):
            #     ds = [(-v, 0), (v, 0), (0, -v), (0, v)]
            #     dx, dy = ds[i]
            #     x2, y2 = (bot['position'].x + dx, bot['position'].y + dy)
            #     gx, gy = get_grid_idx(x2, y2)
            #     if (gx, gy) in bubble_time or (gx, gy) in position_brick['gongfu']:
            #         continue
            #     r2 = (targety - y2) ** 2 + (targetx - x2) ** 2
            #     if r2 < d:
            #         d = r2
            #         nearest = i
            #     datas.append((i, r2 ** 0.5))
            # datas = sorted(datas, key=lambda x: x[1])
            # if len(datas) == 0:
            #     #print('no direct')
            #     r = random(0, 4)
            # else:
            #     nearest = datas[0][0]
            #     if nearest != -1:
            #         r = nearest
    
            #     r  = nearest
            print(571)
            r = None
            print('590 bot and target',botx_grid,boty_grid, (col-1,row))
            if col>=1:
                print('col 1')
                r = get_dir(botx_grid,boty_grid, (col-1,row))
            print(592,r)
            if  r is  None:
                print('not r')
                r = get_dir(botx_grid,boty_grid, (col+1,row))
            print(615,r)
            if r is not None:
                bot['player_state']['current_direction'] =lrud[r]
                dx, dy = ds[int(r)]
                add_bot_mile(bot,v)
                bot_displacement(bot,dx,dy)
            else:
            
                print('do mini plan')
                print(botx_grid,boty_grid, (col-1,row))
        elif bot_attract_other(p,bot, [b for b in bots if b!=bot]):
            if random(0,1)<0.1:
                
                bot_put_bubble(bot, p)
            else:
                bot['walk_target'] = get_random_target(botx_grid,boty_grid)
        elif in_bot_attract_range(p,get_bot_power(bot),(mex, mey)):
            
            bot_put_bubble(bot, p)
        elif bot.get('walk_target'):
            print(bot)
     
            r = get_dir(botx_grid,boty_grid,bot['walk_target'])
            if r is not None:
                bot['player_state']['current_direction'] =lrud[r]
                dx, dy = ds[int(r)]
                add_bot_mile(bot,v)
                bot_displacement(bot,dx,dy)
            elif  (botx_grid,boty_grid)==bot['walk_target']:
               
                bot['walk_target'] = get_random_target(botx_grid,boty_grid)
            else:
                print("????")
   
                bot['walk_target'] = get_random_target(botx_grid,boty_grid)
                
            #r = get_dir(botx_grid,boty_grid, target)
        elif not bot['target']:
 
            bot['walk_target'] =  get_random_target(botx_grid,boty_grid)

def try_boom_bots(boom_grid_pos):
    for bot in bots:
        pp = bot['position']
        gridx, gridy = get_grid_idx(pp.x, pp.y)
        if (gridx, gridy) == boom_grid_pos:
            bot['state'] = 'Dead!'


def draw():
    global winbgm
    global bgm
    global bots
    global bg_window

    #bots = [b for b in bots if b['state'] == 'alive']
    if len(filter(lambda b :b["state"]=='alive',bots)) == 0:
       
        image(player['bg'], 0, 0)
        bgm.stop()
        if winbgm.isPlaying() == False:
            winbgm.play()
        textSize(30)
        title = 'You Win!'
        text(title, 0.5 * w - textWidth(title) * 0.5, 0.5 * h)
    else:
        draw_()
        global mouse_img
        image(mouse_img, mouseX, mouseY)

        textSize(20)
        for i, c in enumerate(['number', 'power', 'speed']):
            n = player_state['obj'][c]
            fill(255)
            text(str(n), i * 50 + 35, 570)
        for i,bot in enumerate(bots):
            fill(255)
            text("bot_"+str(bot['id']),650, 100+i*50)
            text(bot['state'],730, 100+i*50)

def draw_():
    global bg_img
    global bubble_img
    image(bg_window, -20, 0 - 20)
    # background(255)
    image(player['bg'], 0, 0)

    global player
    global player_index
    global player_position
    global current_direction
    global boom
    boom_i = int(millis()/250)%4
    global bubble_animes
    bubble_img = bubble_animes[boom_i]
    global brick_img
    i = player_index[current_direction] % 4
    i = get_walk_img_i()
    img = player[current_direction][i]
    if game_state['update'] % 3 == 0:
        bots_move()
        for px,py in g_paths:
            rect(px * 40,py*40,40,40)
    game_state['update'] += 1

    for x, y in position_brick['gongfu']:
        y, x = get_grid_topleft(y, x)
        image(img_brick['gongfu'], x-3, y-8)
    for x, y in position_brick['box']:
        y, x = get_grid_topleft(y, x)
        image(img_brick['box'], x, y - 10)

    m = {'a': 'left', 'd': 'right', 'w': 'up', 's': 'down'}
    # press once and go forever
    if keyPressed:
        if key in ['a', 'd', 's', 'w']:
            dir = m[key]
            player_index[dir] += 1
            current_direction = dir
        c, r = get_grid_idx(player_position.x, player_position.y)
        forbids = player['bubbles'] + position_brick['gongfu'] + position_brick['box']

        y_, x_ = get_grid_centre(r, c)
        d = {'left': get_grid_centre(r, c - 1), 'right': get_grid_centre(r, c + 1),
             'up': get_grid_centre(r - 1, c), 'down': get_grid_centre(r + 1, c)
             }
        obj_map = get_inverted_obj_map(position_object)
        cur_v = get_player_speed()
        if key in ['a','s','d','w']:
            add_mile(cur_v)
        if key == 'a':
            player_position.x -= cur_v

            if (c - 1, r) in forbids:
                player_position.x = max(grid_w * (c) + 0.5 * grid_w, player_position.x)
                line(grid_w * (c) + 0.5 * grid_w, 0, grid_w * (c) + 0.5 * grid_w, h)
        if key == 'd':
            player_position.x += cur_v
            if (c + 1, r) in forbids:
                # pass

                player_position.x = min(grid_w * (c + 1) - 0.5 * grid_w, player_position.x)

                print(grid_w * (c + 1) - 0.5 * grid_w)

        if key == 'w':
            player_position.y -= cur_v
            if (c, r - 1) in forbids:
                player_position.y = max(grid_h * (r) + 0.5 * grid_h, player_position.y)

        if key == 's':
            player_position.y += cur_v
            if (c, r + 1) in forbids:
                player_position.y = min(grid_h * (r + 1) - 0.5 * grid_h, player_position.y)
        pV = player_position
        name, player_grid_pos = is_player_on_obj(pV, obj_map)
        if name:
            player_state['obj'][name] += 1
            obj_voice.play()
            position_object[name].remove(player_grid_pos)
        textSize(30)
        fill(0)
        text(str(r) + "---" + str(c), 0.5 * w, 0.5 * h)
    player_position.x, player_position.y = limit_player(player_position.x, player_position.y)
    player['bricks'].sort()
    player['bubbles'].sort()
    white_bricks = position_brick['gongfu']
    # boom effect
    global boom_voice
    for x, y in bubble_time.keys():
        t = bubble_time.get((x, y), 10000)
        if t + exptime < millis() < t + endtime:
            if not t + exptime in boom_log:
                boom_log[t + exptime] = (x, y)
                boom_voice.play()
            if (x,y)  in boom_range:
                for boom_x,boom_y in boom_range[(x,y)  ]:
                    y_, x_ = get_grid_topleft(boom_y, boom_x)
                    image(boom, x_, y_,40,40)
            else:
                bubble_p = (x,y)
                y_, x_ = get_grid_topleft(y, x)
                image(boom, x_, y_)
                yc, xc = get_grid_centre(y, x)
                if (x, y) in bubble_power:
                    boom_r = bubble_power[(x, y)]
                else:
                    boom_r = player_state['obj']['power'] + 3
                
                
                def get_part_range(boom_r,x,y ):
                    hitted_bricks = []
                    ranges = []
                    for dx , dy in [(0,1),(1,0),(0,-1),(-1,0)]:
                        for i in range(1, boom_r):
                            newx,newy = x+dx *i, y+dy*i
                            p = (newx,newy)
                            if is_hit_brick(p, white_bricks, position_object):
                                hitted_bricks.append(p)
                                break
                            try_boom_bots(p)
                            ranges.append(p)
                           
                    return ranges,hitted_bricks
                ranges,hitted_bricks = get_part_range(boom_r,x,y )
                new_boom_bubbles = []
                print({'bt':bubble_time})
                for p in bubble_time.keys():
                    if p != (x,y) and p in ranges:
                        new_boom_bubbles.append(p)
                        print({'add boom':p})
                print({'nb':new_boom_bubbles} )
                olds = [(x,y)]
                
                while new_boom_bubbles!=[]:
                    for x,y in new_boom_bubbles:
                        
                        new_ranges,hitted_bricks_ = get_part_range(boom_r,x,y )
                        print({'rm':(x,y)})
                        del bubble_time[(x, y)]
                        hitted_bricks += hitted_bricks_
                        ranges+=new_ranges
                        print({'new_ranges':new_ranges})
                        if (x, y) in player['bubbles']:
                            player['bubbles'].remove((x, y))
                        for bot in bots:
                            if (x, y) in bot['bubbles']:
                                bot['bubbles'].remove((x, y))
                    print('~'*10)
                    new_boom_bubbles = []
                    for p in bubble_time.keys():
                        if p not in olds and p in new_ranges:
                            new_boom_bubbles.append(p)
                for brick in hitted_bricks:
                    if brick in white_bricks:
                        white_bricks.remove(brick) 
                        new_obj(position_object,brick)
                print({'ranges':ranges})
                boom_range[bubble_p] = ranges
                print('_'*20)
            # del bubble_time[(x,y)]
            if (x, y) in player['bubbles']:
                player['bubbles'].remove((x, y))

            else:
                for bot in bots:
                    if (x, y) in bot['bubbles']:
                        bot['bubbles'].remove((x, y))

        elif millis() > t + endtime:
            if (x,y) in bubble_time:
                del bubble_time[(x, y)]
            if (x, y) in boom_range:
                del boom_range[(x, y)]

        else:
            x2, y2 = get_grid_topleft(x, y)
            image(bubble_img, x2, y2)

    def get_player_topleft(img, footx, footy):
        return footx - img.width * 0.5, footy - img.height + 20

    px, py = get_player_topleft(img, player_position.x, player_position.y)
    image(img, px, py)
    fill(255)
    text('Player1', player_position.x, player_position.y + 20 - img.height)
    global p2
    obj_map = get_inverted_obj_map(position_object)
    for bot in bots:
        pV = bot['position']
        obj, bot_grid_p = is_player_on_obj(pV, obj_map)
        if obj:
            bot_add_obj(bot, obj)
            del obj_map[bot_grid_p]
            position_object[obj].remove(bot_grid_p)

    for obj_name, positions in position_object.items():
        for x, y in positions:
            x2, y2 = get_grid_topleft(x, y)
            image(img_object[obj_name], x2, y2 - abs(int(millis()/125)%8  - 4) * 2, 40, 40 * img_object[obj_name].height / img_object[obj_name].width)
    for bot in bots:
        p2 = get_bot_img(bot)
        bot_p = bot['position']
        if bot['state'] == 'Dead!': continue
        bx, by = get_player_topleft(p2, bot_p.x, bot_p.y)
        image(p2, bx, by)
        
        fill(0)
        text('bot_' + str(bot['id']), bot_p.x, bot_p.y - 20)
        text(str(bot['target'])+str(bot.get('walk_target','/')), bot_p.x, bot_p.y - 40)
    p2 = get_p2_img(player2)
    bot_p = player2['position']
    bx, by = get_player_topleft(p2, bot_p.x, bot_p.y)
    image(p2, bx, by)
    
    for bot in bots:
        
        if bot['player_state']['isBot'] is False:
            continue
        
        if bot['state'] !='alive':
            continue
        print('bot')
        print(bot['position'].x, bot['position'].y)
        x2, y2 = get_grid_idx(bot['position'].x, bot['position'].y)
        y2,x2 = get_grid_topleft(y2,x2 )
        stroke(255,0,0)
        print(x2,y2)
        fill(100,100)
        rect(x2, y2,40,40)
    

def img_centre(x, y, img):
    return x + 0.5 * img.width, y + 0.5 * img.height


def grid_map(x, y):
    x_r = x % 40
    x = int(x / 40)
 
    y_r = y % 40

    y = int(y / 40)
 
    return x, y


def check_4_direct_path(x, y):
    global player
    x, y = grid_map(x, y)
    d = {'left': (-40, 0), 'right': (40, 0), 'up': (0, -40), 'down': (0, 40)}
    d_ = {}
    for k, v in d.items():
        dx, dy = v
        x1, y1 = x + dx, y + dy
        p = (x1, y1)

        if p in player['bubbles']:
            d_[k] = (x1, y1)
    return d_


def get_bubble_pos(x, y):
    x, y = grid_map(x, y)
    if not bubble_log.get((x, y), False):
        return x, y
    return None, None


def get_brick_pos(x, y):
    x, y = grid_map(x, y)
    if not brick_log.get((x, y), False):
        return x, y
    return None, None


def mousePressed():
    global player_position
    px, py = player_position.x, player_position.y
    global player
 
    if True:
        px, py = player_position.x, player_position.y
        global player
        x, y = get_grid_idx(px, py)
        if len(player['bubbles']) < get_bubble_limit():
            if (x, y) not in bubble_log:
                bubble_log[(x, y)] = True
                player['bubbles'].append((x, y))
                bubble_time[(x, y)] = millis()


def get_grid_idx(x, y):
    return int(x / grid_w), int(y / grid_h)



def keyPressed():
    if key == 'o':
        p = get_grid_idx(mouseX, mouseY)
        new_obj(position_object,p)
        
    if key == 'n':
        print({'bb':bubblem_time})
    global player2
    print("typed %s %d" % (key, keyCode))
    dir = ''
    if key == CODED:
        print(key)
        if keyCode == UP:
            dir = 'up'
            print('up')
        elif keyCode == DOWN:
            dir = 'down'
        elif keyCode == LEFT:
            dir = 'left'
        elif keyCode == RIGHT:
            dir = 'right'
    if dir !='':
        bot_walk(player2,dir)
    global player_position
    global current_direction
    global player_index

    if key == 'l':
        for b in bots:
            print(b)
   
    if key == 'm':

        p = get_grid_idx(mouseX, mouseY)
        if p not in player['bubbles']:
            # if len(player['bubbles'])< get_bubble_limit():
            player['bubbles'].append(p)
            bubble_time[p] = millis()
    if key == 'k':
        fill(250)
        circle(mouseX, mouseY, 5)
    if key == 'n':
        p = get_grid_idx(mouseX, mouseY)
        if p in player['bubbles']:
            player['bubbles'].remove(p)
    m = {'a': 'left', 'd': 'right', 'w': 'up', 's': 'down'
         }
 
    if key == 'b':
        bot = new_bot()
        bots.append(bot)
    if key == 'q':
        dx = mouseX - player_position.x
        dy = mouseY - player_position.y
        if dx > dy:
            if dx > 0:
                current_direction = 'right'
            else:
                current_direction = 'left'
        else:
            if dy > 0:
                current_direction = 'down'
            else:
                current_direction = 'up'
        dx = max(min(dx, 10), -10)

        dy = max(min(dy, 10), -10)
        player_position.x += dx
        player_position.y += dy
        player_index[current_direction] += 1

    if key == 'j':
        px, py = player_position.x, player_position.y
        global player
        x, y = get_grid_idx(px, py)
        if len(player['bubbles']) < get_bubble_limit():
            if (x, y) not in bubble_time:
                bubble_log[(x, y)] = True
                player['bubbles'].append((x, y))
                bubble_time[(x, y)] = millis()

    if key == 'y':
        px, py = player_position.x, player_position.y
        global player
        px, py = img_centre(px, py, player['down'][0])
        x, y = get_brick_pos(px, py)
        if x and y:
            # bubble_log[(x,y)] = True
            player['bricks'].append((x, y))